package com.personal.dataconvert;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.personal.core.data.DataRow;
import com.personal.core.data.DataTable;
import com.personal.core.utils.Assert;
import com.personal.core.utils.CoreUtil;
import com.personal.dataconvert.bean.CombineColumnConfig;
import com.personal.dataconvert.bean.HeaderConfig;
import com.personal.dataconvert.bean.HtmlConfig;
import com.personal.dataconvert.port.Data2Html;
import com.personal.dataconvert.util.ExcelHtmlUtil;

/**
 * DataTable转Html工具类 DataTable中的tag设置table 的样式 DataColumn tag ：可以设置居左居右的样式
 * dataType : 中可以设置宽度 DataRow 中可以加 TRSTYLE 设置行样式 DataRow 中可以加 columnName +
 * TDSTYLE 设置单元格样式 DataRow 中可以加TRCLICK 设置点击事件 DataRow 中可以加 columnName + TDCLICK
 * 设置点击事件 有点击事件时会拼接<a> 链接
 * @author cuibo
 */
public class DataTable2Html implements Data2Html
{
    /** 报表数据 */
    private DataTable table;
    private List<Object> allObjectData;
    /** 隐藏列 */
    private Set<String> hideColumns;
    /** 合并列配置 */
    private Set<CombineColumnConfig> combineColumnConfigs;
    /** splitFlag 表头分割标记。默认是点 */
    private String splitFlag = ".";
    /** 2017 06 02 新增手动注入HtmlConfig */
    private HtmlConfig htmlConfig;
    /** 处理同名问题 */
    private Map<String, String> sameNameCache;
    /** 是否设置title */
    private boolean withTitle = true;
    /** 开始索引 */
    private int startIndex = -1;
    /** 结束索引 */
    private int endIndex = Integer.MAX_VALUE;
    /** 当前页号 */
    private int currentPage = -1;
    /** 当前页面大小 */
    private int pageSize = -1;
    /** 最大页码 */
    private int maxPage = -1;

    private DataTable2Html()
    {
    }

    private DataTable2Html(Builder builder)
    {
        table = builder.table;
        hideColumns = builder.hideColumns;
        splitFlag = builder.splitFlag;
        combineColumnConfigs = builder.combineColumnConfigs;
        htmlConfig = builder.htmlConfig;
        sameNameCache = builder.sameNameCache;
        withTitle = builder.withTitle;
        startIndex = builder.startIndex;
        endIndex = builder.endIndex;
        pageSize = builder.pageSize;
        currentPage = builder.currentPage;
        loadAllObjectData();
        createHtmlConfig();
        // 如果设置了分页信息则设置分页信息
        setPageInfo();
    }

    @Override
    public String createBody() throws Exception
    {
        if (table == null)
        {
            return "";
        }
        Data2Html data2Html = new ExportData2Html.Builder().setSameNameCache(sameNameCache)
                .setAllObjectData(allObjectData).setHtmlConfig(htmlConfig).setStartIndex(startIndex)
                .setEndIndex(endIndex).build();
        return data2Html.createBody();
    }

    @Override
    public String createHeader() throws Exception
    {
        if (table == null)
        {
            return "";
        }
        Data2Html data2Html = new ExportData2Html.Builder().setSameNameCache(sameNameCache)
                .setAllObjectData(allObjectData).setHtmlConfig(htmlConfig).setStartIndex(startIndex)
                .setEndIndex(endIndex).build();
        return data2Html.createHeader();
    }

    @Override
    public String createHtml() throws Exception
    {
        if (table == null)
        {
            return "";
        }
        Data2Html data2Html = new ExportData2Html.Builder().setSameNameCache(sameNameCache)
                .setAllObjectData(allObjectData).setHtmlConfig(htmlConfig).setStartIndex(startIndex)
                .setEndIndex(endIndex).build();
        return data2Html.createHtml();
    }

    /**
     * 获取下一页的body
     * @return
     * @throws Exception
     */
    public String nextPageBody() throws Exception
    {
        // 检查分页的合法性
        checkPageInfo();
        if (currentPage + 1 > maxPage)
        {
            throw new UnsupportedOperationException("已到最后一页");
        }
        currentPage++;
        setPageInfo();
        Data2Html data2Html = new ExportData2Html.Builder().setSameNameCache(sameNameCache)
                .setAllObjectData(allObjectData).setHtmlConfig(htmlConfig).setStartIndex(startIndex)
                .setEndIndex(endIndex).build();
        return data2Html.createBody();
    }

    /**
     * 获取下一页的html
     * @return
     * @throws Exception
     */
    public String nextPageHtml() throws Exception
    {
        // 检查分页的合法性
        checkPageInfo();
        if (currentPage + 1 > maxPage)
        {
            throw new UnsupportedOperationException("已到最后一页");
        }
        currentPage++;
        setPageInfo();
        Data2Html data2Html = new ExportData2Html.Builder().setSameNameCache(sameNameCache)
                .setAllObjectData(allObjectData).setHtmlConfig(htmlConfig).setStartIndex(startIndex)
                .setEndIndex(endIndex).build();
        return data2Html.createHtml();
    }

    private void checkPageInfo()
    {
        Assert.isTrue(currentPage > 0, "不合法的参数设置！");
        Assert.isTrue(pageSize > 0, "不合法的参数设置！");
    }

    /**
     * 构建HtmlConfig
     * @return
     * @throws Exception
     */
    private void createHtmlConfig()
    {
        if (htmlConfig != null)
        {
            return;
        }
        htmlConfig = new HtmlConfig();
        htmlConfig.setName(table.getTableName());
        htmlConfig.setIrregular(ExcelHtmlUtil.isIrregular(table));
        List<HeaderConfig> headerConfigs = null;
        try
        {
            headerConfigs = ExcelHtmlUtil.createTrees(table, splitFlag, hideColumns);
        } catch (Exception e)
        {
        }
        if (CoreUtil.isEmpty(headerConfigs))
        {
            throw new IllegalArgumentException("datatable信息不合法，创建表头配置失败！");
        }
        htmlConfig.setTableClass(CoreUtil.parseStr(table.getTag()));
        htmlConfig.setHeaderConfigs(headerConfigs);
        htmlConfig.setCombineColumnConfigs(combineColumnConfigs);
        htmlConfig.setWithTitle(withTitle);
    }

    private void loadAllObjectData()
    {
        if (!CoreUtil.checkDataTableHasData(table))
        {
            return;
        }
        allObjectData = new ArrayList<Object>();
        for (DataRow object : table.getRows())
        {
            allObjectData.add(object.getItemMap());
        }
    }

    private void setPageInfo()
    {
        if (currentPage > 0 && pageSize > 0)
        {
            startIndex = (currentPage - 1) * pageSize;
            endIndex = currentPage * pageSize;
            maxPage = CoreUtil.isEmpty(allObjectData) ? 0
                    : allObjectData.size() % 10 == 0 ? allObjectData.size() / pageSize
                            : allObjectData.size() / pageSize + 1;
        }
    }

    /**
     * 建造
     * @author cuibo
     */
    public static class Builder
    {
        private DataTable table;
        private String splitFlag = ".";
        private Set<String> hideColumns;
        private Set<CombineColumnConfig> combineColumnConfigs;
        private HtmlConfig htmlConfig;
        private Map<String, String> sameNameCache;
        private boolean withTitle = true;
        private int startIndex = -1;
        private int endIndex = Integer.MAX_VALUE;
        private int currentPage = -1;
        private int pageSize = -1;

        public Builder addCombineColumn(CombineColumnConfig combineColumnConfig)
        {
            if (combineColumnConfigs == null)
            {
                combineColumnConfigs = new HashSet<CombineColumnConfig>();
            }
            combineColumnConfigs.add(combineColumnConfig);
            return this;
        }

        public DataTable2Html build()
        {
            return new DataTable2Html(this);
        }

        public Builder setCombineColumnConfigs(Set<CombineColumnConfig> combineColumnConfigs)
        {
            this.combineColumnConfigs = combineColumnConfigs;
            return this;
        }

        public Builder setCurrentPage(int currentPage)
        {
            this.currentPage = currentPage;
            return this;
        }

        public Builder setDataTable(DataTable table)
        {
            this.table = table;
            return this;
        }

        public Builder setEndIndex(int endIndex)
        {
            this.endIndex = endIndex;
            return this;
        }

        public Builder setHideColumns(Set<String> hideColumns)
        {
            this.hideColumns = hideColumns;
            return this;
        }

        public Builder setHtmlConfig(HtmlConfig htmlConfig)
        {
            this.htmlConfig = htmlConfig;
            return this;
        }

        public Builder setPageSize(int pageSize)
        {
            this.pageSize = pageSize;
            return this;
        }

        public Builder setSameNameCache(Map<String, String> sameNameCache)
        {
            this.sameNameCache = sameNameCache;
            return this;
        }

        public Builder setSplitFlag(String splitFlag)
        {
            this.splitFlag = splitFlag;
            return this;
        }

        public Builder setStartIndex(int startIndex)
        {
            this.startIndex = startIndex;
            return this;
        }

        public Builder setWithTitle(boolean withTitle)
        {
            this.withTitle = withTitle;
            return this;
        }
    }
}
